using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Runtime.InteropServices;

namespace FOTPService
{
    public partial class Service1 : ServiceBase
    {
        [DllImport("COTPDB.dll")]
        public static extern int OTP_DB_Initialize();

        [DllImport("COTPDB.dll")]
        public static extern void OTP_DB_Finalize();

        [DllImport("COTPDB.dll")]
        public static extern int OTP_DB_Config(int iType, string server, int port, string dbname, string uid, string pwd);

        [DllImport("COTPDB.dll")]
        public static extern int OTP_DB_ImportTokens(string tnkFileName, string licFileName);

        [DllImport("COTPDB.dll")]
        public static extern int OTP_DB_Auth(string user, uint OTP, string pin);

        [DllImport("COTPDB.dll")]
        public static extern int OTP_DB_Sync(string user, uint firstOTP, uint nextOTP);

        [DllImport("COTPDB.dll")]
        public static extern int OTP_DB_AddTokenForUser(string user, string tokenNum);

        [DllImport("COTPDB.dll")]
        public static extern int OTP_DB_DelTokenOfUser(string user, string tokenNum);

        [DllImport("COTPDB.dll")]
        public static extern int OTP_DB_SetPIN(string user, string pin);

        [DllImport("COTPDB.dll")]
        public static extern int OTP_DB_ValidToken(string user, string tokenNum);

        [DllImport("COTPDB.dll")]
        public static extern int OTP_DB_SetNeedPIN(string user, int needPIn);


        private Socket connection; // Socket for accepting a connection 
        private Thread readThread; // Thread for processing incoming messages     
        private NetworkStream socketStream; //network data stream           
        private BinaryWriter writer; // facilitates writing to the stream    
        private BinaryReader reader; // facilitates reading from the stream 

        public Service1()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
            // TODO: Add code here to start your service.
            readThread = new Thread(new ThreadStart(RunServer));
            readThread.Start();
        }

        protected override void OnStop()
        {
            // TODO: Add code here to perform any tear-down necessary to stop your service.
            System.Environment.Exit(System.Environment.ExitCode);
        }

        public void RunServer()
        {
            TcpListener listener;
            //int counter = 1;
            // wait for a client connection and display the text
            // that the client sends
            try
            {
                //create TcpListener                    
                IPAddress local = IPAddress.Parse(GetIPAddress());
                listener = new TcpListener(local, 1917);

                //TcpListener waits for connection request
                listener.Start();
                

                //establish connection upon client request
                while (true)
                {                    
                    // accept an incoming connection     
                    connection = listener.AcceptSocket();
                    
                    // create NetworkStream object associated with socket
                    socketStream = new NetworkStream(connection);
                    socketStream.ReadTimeout = 15 * 1000;
                    // create objects for transferring data across stream
                    writer = new BinaryWriter(socketStream);
                    reader = new BinaryReader(socketStream);
                    
                    string theReply = "";
                    //read string data sent from client                    
                    do
                    {                        
                        try
                        {
                            // read the string sent to the server
                            theReply = reader.ReadString();                           
                            if (theReply.Length >= 56 )
                            {
                                Message mess = new Message(theReply);
                                int iRe = 0;
                                string UserID = mess.UserID;
                                string OTP = mess.OTPNumber;                               
                                //Authenticate
                                iRe = OTP_DB_Auth(UserID, uint.Parse(OTP), "1234");
                                if (iRe == -1)
                                {                                    
                                    mess.ResponseCode = "-1";
                                    writer.Write(mess.Content);
                                }
                                else if (iRe < 10)
                                {
                                    mess.ResponseCode = "0"+iRe;
                                    writer.Write(mess.Content);                                   
                                }
                                else {
                                    mess.ResponseCode = "" + iRe;
                                    writer.Write(mess.Content);
                                }                                
                            }
                        } // end try
                        catch (Exception ee)
                        {                           
                            break;
                        } // end catch
                    } while (connection.Connected);
                    //User terminated connection;
                    //close connection  
                    writer.Close();
                    reader.Close();
                    socketStream.Close();
                    connection.Close();                  
                } // end while
            } // end try
            catch (Exception error)
            {               
                //MessageBox.Show(error.ToString());
            } // end catch
        } // end method RunServer

        private string GetIPAddress()
        {
            string strHostName = "";
            string ipaddr = "";
            strHostName = Dns.GetHostName();
            IPHostEntry ipEntry = Dns.GetHostEntry(strHostName);
            IPAddress[] addr = ipEntry.AddressList;
            for (int i = 0; i < addr.Length; i++)
            {
                ipaddr = addr[i].ToString();
            }
            return ipaddr;
        }

        
    }
}
